﻿using System;
using System.Deployment.Application;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Configuration;
using System.Diagnostics;
using System.IO;
using System.Management.Automation;
using System.Management.Automation.Runspaces;
using System.Reflection;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Threading;
using CmdletDesigner;
using System.Web.Security;
using System.Web.ClientServices.Providers;
using System.Net;
//using System.Windows.Forms;
using System.Web.ClientServices;
using WPF.Themes;

namespace Microsoft.PowerShell.CmdletManagement
{
    /// <summary>
    /// Interaction logic for CmdletDesigner.xaml
    /// </summary>
    public partial class CmdletDesigner : Window
    {
        private const string DefaultServiceUri = "http://www.snapins.com/api/cmdlet.asmx";
        private Uri ServiceUri = new Uri(DefaultServiceUri);

        private List<PsSpecCmdlet> _backgroundLoadedCmdlets;
        private string _backgroundStringOutput;
        private ICollectionView _cmdletCollectionView = null;
        private ListSortDirection _lastCmdletDirection = ListSortDirection.Ascending;
        private GridViewColumnHeader _lastCmdletHeaderClicked = null;
        private ListSortDirection _lastProjectDirection = ListSortDirection.Ascending;
        private GridViewColumnHeader _lastProjectHeaderClicked = null;
        private readonly object _lockObject = new object();
        private List<PsSpecNoun> _nounList;
        private ICollectionView _parameterCollectionView = null;
        private ICollectionView _projectCollectionView = null;
        private List<PsSpecProject> _projects;
        private PsSpecProject _currentProject;

        private Runspace _runspace;
        private string _serviceUri;
        private ArrayList _verbList;
        private bool _isGuest;

        public CmdletDesigner()
        {
            InitializeComponent();
            AppDomain.CurrentDomain.UnhandledException +=
                new UnhandledExceptionEventHandler(CurrentDomain_UnhandledException);

            //ThemeManager.SetTheme(this, "ExpressionLight");

            CmdletTab.Visibility = Visibility.Hidden;

            if (ConfigurationManager.AppSettings["ServiceUri"] != null)
            {
                ServiceUri = new Uri(ConfigurationManager.AppSettings["ServiceUri"]);
            }

            SetDefaultPrincipal();

            SetApplicationVersion();

            Show();

            //InstallSnapin();
            CreatePowerShellRunspace();
            LoadProject();
        }

        private void SetApplicationVersion()
        {
            if (ApplicationDeployment.IsNetworkDeployed)
            {
                lblAppVersion.Content = "Version: " + ApplicationDeployment.CurrentDeployment.CurrentVersion;
            }
        }

        private void SetDefaultPrincipal()
        {
            AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.UnauthenticatedPrincipal);
        }

        private ICollectionView ParameterCollectionView
        {
            get
            {
                if (_parameterCollectionView == null)
                {
                    lock (_lockObject)
                    {
                        if (_parameterCollectionView == null)
                        {
                            _parameterCollectionView = CollectionViewSource.GetDefaultView(ParameterSelector.DataContext);

                            if (_parameterCollectionView != null)
                            {
                                _parameterCollectionView.Filter = new Predicate<object>(ParameterTextFilter);
                                _parameterCollectionView.SortDescriptions.Add(new SortDescription("Name",
                                                                                                 ListSortDirection.
                                                                                                     Ascending));
                            }
                        }
                    }
                }

                return _parameterCollectionView;
            }
        }

        private ICollectionView CmdletCollectionView
        {
            get
            {
                if (_cmdletCollectionView == null)
                {
                    lock (_lockObject)
                    {
                        if (_cmdletCollectionView == null)
                        {
                            _cmdletCollectionView = CollectionViewSource.GetDefaultView(Cmdlets.DataContext);

                            if (_cmdletCollectionView != null)
                            {
                                _cmdletCollectionView.Filter = new Predicate<object>(CmdletTextFilter);

                                _cmdletCollectionView.SortDescriptions.Clear();
                                SortDescription sd = new SortDescription("Verb", ListSortDirection.Ascending);
                                _cmdletCollectionView.SortDescriptions.Add(sd);
                                _cmdletCollectionView.Refresh();
                            }
                        }
                    }
                }

                return _cmdletCollectionView;
            }
        }

        private ICollectionView ProjectCollectionView
        {
            get
            {
                if (_projectCollectionView == null)
                {
                    lock (_lockObject)
                    {
                        if (_projectCollectionView == null)
                        {
                            _projectCollectionView = CollectionViewSource.GetDefaultView(Projects.DataContext);

                            if (_projectCollectionView != null)
                            {
                                _projectCollectionView.Filter = new Predicate<object>(ProjectTextFilter);

                                _projectCollectionView.SortDescriptions.Clear();
                                SortDescription sd = new SortDescription("Name", ListSortDirection.Ascending);
                                _projectCollectionView.SortDescriptions.Add(sd);
                                _projectCollectionView.Refresh();
                            }
                        }
                    }
                }

                return _projectCollectionView;
            }
        }

        private void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
        {
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.FileName = "mailto:oising@gmail.com?Subject=Cmdlet Designer Error Report";
            processStartInfo.UseShellExecute = true;

            Process.Start(processStartInfo);

            Thread.Sleep(500);
            Activate();

            MessageTextBox messageTextBox = new MessageTextBox(this);
            messageTextBox.Title = "PowerShell Cmdlet Designer Error";
            messageTextBox.Text = "PowerShell Cmdlet Designer has encountered an error and needs to close.\n\n" +
                                  "We apologize for the inconvenience. Details of this error are included below. Please copy and " +
                                  "paste this into the mail window that has just opened.\n\n";
            messageTextBox.Text += e.ExceptionObject.ToString();

            messageTextBox.ShowDialog();

            Environment.Exit(1);
        }

        private void RetrieveUserRoles(string projectName)
        {
            IDictionary properties = Application.Current.Properties;
            StringBuilder builder = new StringBuilder("Role: ");
            bool isGuest = true;

            properties["IsProjectOwner"] = false;
            properties["IsSpecWriter"] = false;
            properties["IsHelpWriter"] = false;

            // See if they are a project owner
            if (IsUserInRole(projectName, PsSpecProjectRole.ProjectOwner))
            {
                properties["IsProjectOwner"] = true;
                properties["IsSpecWriter"] = true;
                properties["IsHelpWriter"] = true;

                builder.Append("ProjectOwner, SpecWriter, HelpWriter");
                isGuest = false;
            }

            // See if they are a spec writer
            if (IsUserInRole(projectName, PsSpecProjectRole.SpecWriter))
            {
                properties["IsSpecWriter"] = true;

                builder.Append("SpecWriter");
                isGuest = false;
            }

            // See if they are a help writer
            if (IsUserInRole(projectName, PsSpecProjectRole.HelpWriter))
            {
                properties["IsHelpWriter"] = true;

                builder.Append("HelpWriter");
                isGuest = false;
            }

            if (isGuest)
            {
                builder.Append("Guest");
            }

            lblRole.Content = builder.ToString();
        }

        private bool IsUserInRole(string projectName, PsSpecProjectRole role)
        {
            IIdentity currentIdentity;

            if (CmdletDesignerUtils.TryGetIdentity(out currentIdentity) &&
                currentIdentity.IsAuthenticated)
            {
                string userName = currentIdentity.Name;

                GetPsSpecUserPermissionCommand userCommand =
                    new GetPsSpecUserPermissionCommand
                        {
                            ProjectName = projectName,
                            ServiceUri = ServiceUri,
                            User = userName,
                            Role = role
                        };

                try
                {
                    foreach (PsSpecUserPermission userInRole in userCommand.Invoke<PsSpecUserPermission>())
                    {
                        return true;
                    }
                }
                catch (Exception e)
                {
                    if (e.Message.Contains("Could not find user"))
                        return false;
                    else
                        throw;
                }
            }
            return false;
        }

        private List<PsSpecUserPermission> GetUserList(string projectName)
        {
            GetPsSpecUserPermissionCommand userCommand = new GetPsSpecUserPermissionCommand();
            userCommand.ProjectName = projectName;
            userCommand.ServiceUri = ServiceUri;

            List<PsSpecUserPermission> users = new List<PsSpecUserPermission>();
            foreach (PsSpecUserPermission userInRole in userCommand.Invoke<PsSpecUserPermission>())
            {
                users.Add(userInRole);
            }

            return users;
        }

        private void CreatePowerShellRunspace()
        {
            _runspace = RunspaceFactory.CreateRunspace();
            _runspace.Open();

            CmdletDesignerUtils.EnsureCmdletDesignerModule(_runspace, this);
        }

        //private void InstallSnapin()
        //{
        //    RunspaceConfiguration rsConfig = RunspaceConfiguration.Create();

        //    _runspace = RunspaceFactory.CreateRunspace(rsConfig);
        //    _runspace.Open();

        //    using (Pipeline pipeline = _runspace.CreatePipeline())
        //    {
        //        string commandPath = Path.Combine(
        //            Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
        //            "Install-PsSpecCmdletSnapin.ps1");

        //        Command command = new Command(commandPath);
        //        pipeline.Commands.Add(command);

        //        string errors = "";

        //        try
        //        {
        //            Collection<PSObject> results = pipeline.Invoke();
        //        }
        //        catch (Exception e)
        //        {
        //            errors += e.Message;
        //        }

        //        if (pipeline.Error.Count > 0)
        //        {
        //            foreach (PSObject error in pipeline.Error.ReadToEnd())
        //            {
        //                errors += error.ToString();
        //            }
        //        }

        //        if (!String.IsNullOrEmpty(errors))
        //        {
        //            errors += "\n\nPlease see http://TODO_HELP_PAGE for further assistance.";

        //            MessageTextBox messageTextBox = new MessageTextBox(this);
        //            messageTextBox.Title = "Could not install snapin";
        //            messageTextBox.Text = "Could not install snapin.\n\n" + errors;
        //            messageTextBox.ShowDialog();
        //        }
        //    }

        //    _runspace.Close();
        //}

        protected override void OnClosing(CancelEventArgs e)
        {
            bool cancelClose = HasUnsavedChanges();

            if (!cancelClose)
            {
                base.OnClosing(e);
            }
        }

        private bool HasUnsavedChanges()
        {
            string message = "You have unsaved {0} changes. Do you want to save the changes?";
            string changelist = "";

            if (HasChangedNoun())
            {
                if (changelist.Length > 0)
                    changelist += ", ";

                changelist += "noun";
            }

            if (HasChangedCmdlet())
            {
                if (changelist.Length > 0)
                    changelist += ", ";

                changelist += "cmdlet detail";
            }

            if (HasChangedParameter())
            {
                if (changelist.Length > 0)
                    changelist += ", ";

                changelist += "cmdlet parameter";
            }

            if (HasChangedParameterEntry())
            {
                if (changelist.Length > 0)
                    changelist += ", ";

                changelist += "parameter set entry";
            }

            if (!String.IsNullOrEmpty(changelist))
            {
                MessageBoxResult result = MessageBox.Show(
                    String.Format(message, changelist),
                    "You have unsaved changes.", MessageBoxButton.YesNoCancel);

                if (result == MessageBoxResult.Yes)
                {
                    bool saveSuccessful = SaveChanges(false);

                    if (!saveSuccessful)
                    {
                        return true;
                    }
                }
                else if (result == MessageBoxResult.Cancel)
                {
                    return true;
                }
            }

            return false;
        }

        // They clicked "File a Bug"
        private void Click_FileBug(object sender, RoutedEventArgs e)
        {
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.FileName = "mailto:TODO_SUPPORT_ADDRESS?Subject=Feedback on Cmdlet Designer Tool";
            processStartInfo.UseShellExecute = true;

            Process.Start(processStartInfo);
        }

        // They clicked "Go to Website"
        private void Click_WebsiteLink(object sender, RoutedEventArgs e)
        {
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.FileName = "http://TODO_SUPPORT_PAGE";
            processStartInfo.UseShellExecute = true;

            Process.Start(processStartInfo);
        }

        // They clicked "Automation Console"
        private void Click_AutomationConsole(object sender, RoutedEventArgs e)
        {
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.FileName = "PowerShell";

            CmdletDesignerUtils.EnsureCmdletDesignerModule(_runspace, this);

            string startupScript = "'Get-Command -Module CommandDesigner'; " +
                                   "if(-not (Get-Module CommandDesigner)) { " +
                                   "   Import-Module CommandDesigner }; " +
                                   "Get-Command -Module CommandDesigner; ";

            processStartInfo.Arguments = "-NoExit -Command " + startupScript;

            Process.Start(processStartInfo);
        }


        // They clicked "Help"
        private void Click_Help(object sender, RoutedEventArgs e)
        {
            ProcessStartInfo processStartInfo = new ProcessStartInfo();
            processStartInfo.FileName = "http://psstudio.codeplex.com";
            processStartInfo.UseShellExecute = true;

            Process.Start(processStartInfo);
        }

        // They Doubleclicked FontSlider -> We reset to initial value
        private void DoubleClick_FontSlider(object sender, MouseButtonEventArgs e)
        {
            FontSlider.Value = 12;
        }

        // They clicked "Load Project"
        private void Click_LoadProject(object sender, RoutedEventArgs e)
        {
            SelectProjectAndExit();
        }

        // They clicked New Project button
        private void Click_NewProject(object sender, RoutedEventArgs e)
        {
            NewProject();
        }

        // They clicked "Save Changes"
        private void Click_SaveChanges(object sender, RoutedEventArgs e)
        {
            SaveChanges(true);
        }



        public bool IsLoggedIn
        {
            get { return (bool)GetValue(IsLoggedInProperty); }
            set { SetValue(IsLoggedInProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsLoggedIn.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsLoggedInProperty =
            DependencyProperty.Register("IsLoggedIn", typeof(bool), typeof(CmdletDesigner), new UIPropertyMetadata(false));

        private bool SaveChanges(bool refreshUi)
        {
            bool projectRefreshRequired = false;
            bool cmdletRefreshRequired = false;
            bool saveSuccessful = true;

            // Save the currently open cmdlet, if any
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;

            if (current == null)
            {
                cmdletRefreshRequired = false;
            }
            else
            {
                // Save the currently open cmdlet
                if (HasChangedCmdlet())
                {
                    saveSuccessful = saveSuccessful && SaveCmdlet(_runspace);
                    cmdletRefreshRequired = true;
                }

                // Save the currently open parameters
                if (HasChangedParameter())
                {
                    saveSuccessful = saveSuccessful && SaveParameters(_runspace);
                    cmdletRefreshRequired = true;
                }

                // Save the currently open parameter set entries
                if (HasChangedParameterEntry())
                {
                    saveSuccessful = saveSuccessful && SaveParameterSetEntries(_runspace);
                    cmdletRefreshRequired = true;
                }
            }

            // Save any nouns
            if (HasChangedNoun())
            {
                saveSuccessful = saveSuccessful && SaveNouns(_runspace);
                projectRefreshRequired = true;
                cmdletRefreshRequired = true;
            }


            if (refreshUi)
            {
                // Reload the the project data if they've changed the nouns,
                // as that changes cmdlet names as well.
                if (projectRefreshRequired)
                {
                    LoadProjectData(true);
                }
                if (cmdletRefreshRequired)
                {
                    // Changing the noun may have changed information about the active
                    // cmdlet, so refresh it
                    if ((current != null) && (projectRefreshRequired))
                    {
                        foreach (PsSpecCmdlet cmdlet in Cmdlets.ItemsSource)
                        {
                            if (cmdlet.Id == current.Id)
                            {
                                current = cmdlet;
                                break;
                            }
                        }
                    }

                    // Populate the information about the current cmdlet
                    PopulateCmdletData(current, true);
                }
            }

            return saveSuccessful;
        }

        // Save a cmdlet
        private bool SaveCmdlet(Runspace runspace)
        {
            PsSpecCmdlet original = (PsSpecCmdlet)Application.Current.Properties["OriginalCmdlet"];
            PsSpecCmdlet updated = (PsSpecCmdlet)CmdletSummaryContent.DataContext;
            bool saveSuccessful = true;

            if ((original == null) || (updated == null))
            {
                MessageBox.Show("There is no cmdlet to save.");
                return saveSuccessful;
            }

            // $currentCmdlet | Set-PsSpecCmdlet
            using (Pipeline pipeline = runspace.CreatePipeline())
            {
                Command updateCommand = new Command("Set-PsSpecCmdlet");
                updateCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Input.Write(updated);
                pipeline.Commands.Add(updateCommand);

                Collection<PSObject> results = pipeline.Invoke();
                if (pipeline.Error.Count > 0)
                {
                    HandleErrors(pipeline);
                    saveSuccessful = false;
                }
            }

            return saveSuccessful;
        }

        // Handle any errors that come as a result of a PowerShell
        // command
        private static void HandleErrors(Pipeline pipeline)
        {
            if (pipeline.Error.Count > 0)
            {
                string errors = "";

                foreach (PSObject error in pipeline.Error.ReadToEnd())
                {
                    errors += error.ToString();
                }

                CmdletDesignerUtils.HandleException("Error executing command",
                                                    "There were errors executing your command: " + errors,
                                                    null);
            }
        }

        // Determine if a specific cmdlet has changed
        private bool HasChangedCmdlet()
        {
            PsSpecCmdlet original = (PsSpecCmdlet)Application.Current.Properties["OriginalCmdlet"];
            PsSpecCmdlet updated = (PsSpecCmdlet)CmdletSummaryContent.DataContext;

            if ((original == null) || (updated == null))
            {
                return false;
            }

            return (!original.Equals(updated));
        }

        // Determine if any noun in the noun list has changed
        private bool HasChangedNoun()
        {
            List<PsSpecNoun> originalNouns =
                (List<PsSpecNoun>)Application.Current.Properties["OriginalNouns"];

            List<PsSpecNoun> updatedNouns = (List<PsSpecNoun>)NounList.DataContext;
            if ((originalNouns == null) || (updatedNouns == null))
            {
                return false;
            }

            if (originalNouns.Count != updatedNouns.Count)
            {
                return true;
            }

            for (int counter = 0; counter < originalNouns.Count; counter++)
            {
                PsSpecNoun currentOriginalNoun = originalNouns[counter];
                PsSpecNoun currentUpdatedNoun = updatedNouns[counter];

                if (AreNounsDifferent(currentOriginalNoun, currentUpdatedNoun))
                {
                    return true;
                }
            }

            return false;
        }

        // Save the list of nouns in the noun list
        private bool SaveNouns(Runspace runspace)
        {
            bool saveSuccessful = true;

            List<PsSpecNoun> originalNouns =
                (List<PsSpecNoun>)Application.Current.Properties["OriginalNouns"];
            List<PsSpecNoun> updatedNouns =
                (List<PsSpecNoun>)NounList.DataContext;

            if ((originalNouns == null) || (updatedNouns == null))
            {
                MessageBox.Show("There are no nouns to save.");
                return saveSuccessful;
            }

            for (int counter = 0; counter < originalNouns.Count; counter++)
            {
                PsSpecNoun currentOriginalNoun = originalNouns[counter];
                PsSpecNoun currentUpdatedNoun = updatedNouns[counter];

                // But only save nouns that have changed
                if (AreNounsDifferent(currentOriginalNoun, currentUpdatedNoun))
                {
                    // $currentNoun | Set-PsSpecNoun
                    using (Pipeline pipeline = runspace.CreatePipeline())
                    {
                        Command updateCommand = new Command("Set-PsSpecNoun");
                        updateCommand.Parameters.Add("ServiceUri", ServiceUri);

                        pipeline.Input.Write(currentUpdatedNoun);
                        pipeline.Commands.Add(updateCommand);

                        Collection<PSObject> results = pipeline.Invoke();
                        if (pipeline.Error.Count > 0)
                        {
                            HandleErrors(pipeline);
                            saveSuccessful = false;
                        }
                    }
                }
            }

            return saveSuccessful;
        }

        // Save any parameters that have changed on a cmdlet
        private bool SaveParameters(Runspace runspace)
        {
            bool saveSuccessful = true;
            List<PsSpecCmdletParameter> originalParameters =
                (List<PsSpecCmdletParameter>)Application.Current.Properties["OriginalParameters"];
            List<PsSpecCmdletParameterDetails> updatedParameters =
                (List<PsSpecCmdletParameterDetails>)ParameterSelector.DataContext;

            if ((originalParameters == null) || (updatedParameters == null))
            {
                MessageBox.Show("There are no parameters to save.");
                return saveSuccessful;
            }

            for (int counter = 0; counter < originalParameters.Count; counter++)
            {
                PsSpecCmdletParameter currentOriginalParameter = originalParameters[counter];
                PsSpecCmdletParameterDetails currentUpdatedParameter = updatedParameters[counter];

                // But only the parameters that have actually changed
                if (AreParametersDifferent(currentOriginalParameter, currentUpdatedParameter))
                {
                    // $currentParameter | Set-PsSpecCmdletParameter
                    using (Pipeline pipeline = runspace.CreatePipeline())
                    {
                        Command updateCommand = new Command("Set-PsSpecCmdletParameter");
                        updateCommand.Parameters.Add("ServiceUri", ServiceUri);

                        pipeline.Input.Write(currentUpdatedParameter);
                        pipeline.Commands.Add(updateCommand);

                        Collection<PSObject> results = pipeline.Invoke();
                        if (pipeline.Error.Count > 0)
                        {
                            HandleErrors(pipeline);
                            saveSuccessful = false;
                        }
                    }
                }
            }

            return saveSuccessful;
        }

        // Determine if any parameters have changed
        private bool HasChangedParameter()
        {
            List<PsSpecCmdletParameter> originalParameters =
                (List<PsSpecCmdletParameter>)Application.Current.Properties["OriginalParameters"];
            List<PsSpecCmdletParameterDetails> updatedParameters =
                (List<PsSpecCmdletParameterDetails>)ParameterSelector.DataContext;

            if ((originalParameters == null) || (updatedParameters == null))
            {
                return false;
            }

            for (int counter = 0; counter < originalParameters.Count; counter++)
            {
                PsSpecCmdletParameter currentOriginalParameter = originalParameters[counter];
                PsSpecCmdletParameterDetails currentUpdatedParameter = updatedParameters[counter];

                // Find the parameter set grouping editor for this parameter
                ContentPresenter parameterPresenter =
                    (ContentPresenter)
                    PsSpecCmdletParametersContent.ParameterList.ItemContainerGenerator.ContainerFromIndex(counter);

                if (parameterPresenter != null)
                {
                    try
                    {
                        PsSpecCmdletParameterControl parameterControl =
                            (PsSpecCmdletParameterControl)
                            parameterPresenter.ContentTemplate.FindName("Parameter", parameterPresenter);

                        // Apply changes
                        parameterControl.ApplyChanges();
                    }
                    catch (InvalidOperationException)
                    {
                        // We sometimes get an InvalidOperationException if WPF hasn't had the chance
                        // to apply the template yet. In that case, they haven't made a change to
                        // that parameter, and we don't need to apply changes.
                    }
                }

                // Compare the actual parameter
                if (AreParametersDifferent(currentOriginalParameter, currentUpdatedParameter))
                {
                    return true;
                }
            }

            return false;
        }

        // Determine if a specific parameter has changed
        private bool AreParametersDifferent(PsSpecCmdletParameter currentOriginalParameter,
                                            PsSpecCmdletParameterDetails currentUpdatedParameter)
        {
            return (currentUpdatedParameter.CompareTo(currentOriginalParameter) != 0);
        }

        // Determine if a specific noun has changed
        private bool AreNounsDifferent(PsSpecNoun currentOriginalNoun,
                                       PsSpecNoun currentUpdatedNoun)
        {
            return !currentUpdatedNoun.Equals(currentOriginalNoun);
        }

        // Save any parameters set entries that have changed on a cmdlet
        private bool SaveParameterSetEntries(Runspace runspace)
        {
            bool saveSuccessful = true;

            List<PsSpecCmdletParameterSetEntry> originalParameterEntries =
                (List<PsSpecCmdletParameterSetEntry>)Application.Current.Properties["OriginalParameterEntries"];
            List<PsSpecCmdletParameterSetEntry> updatedParameterEntries =
                (List<PsSpecCmdletParameterSetEntry>)PsSpecCmdletParameterEntriesContent.DataContext;

            if ((originalParameterEntries == null) || (updatedParameterEntries == null))
            {
                MessageBox.Show("There are no parameter entries to save.");
                return saveSuccessful;
            }

            // Lists that expose parameter set entries that have been added,
            // removed, and updated
            List<PsSpecCmdletParameterSetEntry> newEntries = new List<PsSpecCmdletParameterSetEntry>();
            List<PsSpecCmdletParameterSetEntry> removedEntries = new List<PsSpecCmdletParameterSetEntry>();
            List<PsSpecCmdletParameterSetEntry> updatedEntries = new List<PsSpecCmdletParameterSetEntry>();
            bool foundInUpdatedSet = false;

            // Detect the updates and removals. We go through the original parameter entries
            // that we cached when we loaded the cmdlet, and compare those to the ones
            // that currently exist in the data set
            foreach (PsSpecCmdletParameterSetEntry originalEntry in originalParameterEntries)
            {
                foundInUpdatedSet = false;

                foreach (PsSpecCmdletParameterSetEntry updatedEntry in updatedParameterEntries)
                {
                    // Detect any updates to a parameter
                    if (originalEntry.Id == updatedEntry.Id)
                    {
                        foundInUpdatedSet = true;

                        if (AreParameterEntriesDifferent(originalEntry, updatedEntry))
                        {
                            updatedEntries.Add(updatedEntry);
                        }
                    }
                }

                // If we didn't find the original entry in the current data set,
                // then they've deleted that parameter entry
                if (!foundInUpdatedSet)
                {
                    // Detect the removals
                    removedEntries.Add(originalEntry);
                }
            }

            // Detect the additions. These will be in the current data set
            // with an ID of -1
            foreach (PsSpecCmdletParameterSetEntry updatedEntry in updatedParameterEntries)
            {
                if (updatedEntry.Id == -1)
                {
                    newEntries.Add(updatedEntry);
                }
            }

            // Process the updates
            foreach (PsSpecCmdletParameterSetEntry currentUpdatedParameter in updatedEntries)
            {
                // $currentParameterSetEntry | Set-PsSpecCmdletParameterSetEntry
                using (Pipeline pipeline = runspace.CreatePipeline())
                {
                    Command updateCommand = new Command("Set-PsSpecCmdletParameterSetEntry");
                    updateCommand.Parameters.Add("ServiceUri", ServiceUri);

                    pipeline.Input.Write(currentUpdatedParameter);
                    pipeline.Commands.Add(updateCommand);

                    Collection<PSObject> results = pipeline.Invoke();
                    if (pipeline.Error.Count > 0)
                    {
                        HandleErrors(pipeline);
                        saveSuccessful = false;
                    }
                }
            }

            // Process the additions
            foreach (PsSpecCmdletParameterSetEntry currentUpdatedParameter in newEntries)
            {
                // $currentParameterSetEntry | Add-PsSpecCmdletParameterSetEntry
                using (Pipeline pipeline = runspace.CreatePipeline())
                {
                    Command updateCommand = new Command("Add-PsSpecCmdletParameterSetEntry");
                    updateCommand.Parameters.Add("ServiceUri", ServiceUri);

                    pipeline.Input.Write(currentUpdatedParameter);
                    pipeline.Commands.Add(updateCommand);

                    Collection<PSObject> results = pipeline.Invoke();
                    if (pipeline.Error.Count > 0)
                    {
                        HandleErrors(pipeline);
                        saveSuccessful = false;
                    }
                }
            }

            // Process the removals
            foreach (PsSpecCmdletParameterSetEntry currentUpdatedParameter in removedEntries)
            {
                // $currentParameterSetEntry | Remove-PsSpecCmdletParameterSetEntry
                using (Pipeline pipeline = runspace.CreatePipeline())
                {
                    Command updateCommand = new Command("Remove-PsSpecCmdletParameterSetEntry");
                    updateCommand.Parameters.Add("ServiceUri", ServiceUri);

                    pipeline.Input.Write(currentUpdatedParameter);
                    pipeline.Commands.Add(updateCommand);

                    Collection<PSObject> results = pipeline.Invoke();
                    if (pipeline.Error.Count > 0)
                    {
                        HandleErrors(pipeline);
                        saveSuccessful = false;
                    }
                }
            }

            return saveSuccessful;
        }

        // Determine if they've changed any parameter set entries
        private bool HasChangedParameterEntry()
        {
            List<PsSpecCmdletParameterSetEntry> originalParameterEntries =
                (List<PsSpecCmdletParameterSetEntry>)Application.Current.Properties["OriginalParameterEntries"];
            List<PsSpecCmdletParameterSetEntry> updatedParameterEntries =
                (List<PsSpecCmdletParameterSetEntry>)PsSpecCmdletParameterEntriesContent.DataContext;

            if ((originalParameterEntries == null) || (updatedParameterEntries == null))
            {
                return false;
            }

            // Detect if they've added or removed any
            if (originalParameterEntries.Count != updatedParameterEntries.Count)
            {
                return true;
            }

            // Then, check each individual parameter set entry
            for (int counter = 0; counter < originalParameterEntries.Count; counter++)
            {
                PsSpecCmdletParameterSetEntry currentOriginalParameter = originalParameterEntries[counter];
                PsSpecCmdletParameterSetEntry currentUpdatedParameter = updatedParameterEntries[counter];

                if (AreParameterEntriesDifferent(currentOriginalParameter, currentUpdatedParameter))
                {
                    return true;
                }
            }

            return false;
        }

        // Compare two specific parameter set entries
        private bool AreParameterEntriesDifferent(PsSpecCmdletParameterSetEntry currentOriginalParameter,
                                                  PsSpecCmdletParameterSetEntry currentUpdatedParameter)
        {
            return (!currentOriginalParameter.Equals(currentUpdatedParameter));
        }

        // Load a project using the project dialog
        private void LoadProject()
        {
            if (HasUnsavedChanges())
                return;
            SelectProject(ServiceUri.ToString(), this);
            Projects.DataContext = null;
        }


        private void SelectProject(string serviceUri, Window owner)
        {
            this._serviceUri = serviceUri;
            Projects.Focus();
            Thread t = new Thread(new ThreadStart(GetProjects));
            t.IsBackground = true;
            t.Start();
        }

        private void GetProjects()
        {
            GetPsSpecProjectCommand command = new GetPsSpecProjectCommand();
            command.ServiceUri = new Uri(_serviceUri);

            List<PsSpecProject> results = new List<PsSpecProject>();
            IEnumerable pipelineResults = new Object[0];
            pipelineResults = command.Invoke();

            try
            {
                foreach (PsSpecProject result in pipelineResults)
                {
                    results.Add(result);
                }
            }
            catch (Exception exception)
            {
                CmdletDesignerUtils.HandleException("Error loading projects",
                                                    "There were errors loading the list of projects.",
                                                    exception);
            }

            _projects = results;
            Dispatcher.Invoke(DispatcherPriority.Normal, new UpdateProjectsDelegate(UpdateProjects));
        }

        private void UpdateProjects()
        {
            if (Projects.DataContext == null)
            {
                if (Projects.Items.Count > 0)
                {
                    Projects.Items.Clear();
                }
                DoDataContext();
            }
        }

        private void DoDataContext()
        {
            Projects.DataContext = null;
            Projects.DataContext = _projects;
            ProgressIndicator.Visibility = Visibility.Hidden;
            ProjectSearch.Focus();
        }

        private void DoubleClick_SelectProject(Object sender, MouseButtonEventArgs e)
        {
            SelectProjectAndExit();
        }

        private void Click_SelectProject(Object sender, RoutedEventArgs e)
        {
            SelectProjectAndExit();
        }

        private void SelectProjectAndExit()
        {
            if (Projects.SelectedItems.Count > 0)
            {
                Application.Current.Properties["SelectedProject"] = Projects.SelectedItem;
                LoadProjectData(false);

                lblProject.Content = "Project: " + ((PsSpecProject)Projects.SelectedItem).Name;
            }
        }

        // Create a NewProject using the project dialog
        private void NewProject()
        {
            if (HasUnsavedChanges())
                return;

            NewProject newProjectDialog = new NewProject(ServiceUri.ToString(), this);
            if ((bool)newProjectDialog.ShowDialog())
            {
                LoadProject();
            }
        }

        // Load the information required when changing projects
        private void LoadProjectData(bool refreshSameProject)
        {
            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];

            if (selectedProject == null)
            {
                MessageBox.Show("Please select a project.");
                return;
            }

            // Populate the Users tab with the projects users.
            LoadProjectUsers(selectedProject.Name);

            // Set the default From and TO Dates in the History tab
            InitializeHistoryTab();

            // Refresh their user roles
            RetrieveUserRoles(selectedProject.Name);
            UpdateUIForRole();

            // Populate the verbs and nouns from the project
            PopulateVerbsAndNouns(true);

            // If we're only doing a refresh of the same project,
            // try to keep their selected cmdlet
            int previouslySelectedCmdletId = -1;
            if (refreshSameProject)
            {
                PsSpecCmdlet currentlySelected = Cmdlets.SelectedItem as PsSpecCmdlet;
                if (currentlySelected != null)
                {
                    previouslySelectedCmdletId = currentlySelected.Id;
                }
            }

            ReloadCmdlets(selectedProject);

            // Restore their selected cmdlet
            if (refreshSameProject)
            {
                foreach (PsSpecCmdlet current in ((List<PsSpecCmdlet>)Cmdlets.DataContext))
                {
                    if (current.Id == previouslySelectedCmdletId)
                    {
                        Cmdlets.SelectedItem = current;
                        break;
                    }
                }
            }
            _cmdletCollectionView = null;

            // If we're loading a new project, reset the view of the different tabs
            if (!refreshSameProject)
            {
                CmdletTab.Visibility = Visibility.Hidden;
                NounsTab.Visibility = Visibility.Visible;
                CmdletsListTab.Visibility = Visibility.Visible;
                NavigationTabs.SelectedItem = CmdletsListTab;
                PermissionTab.Visibility = Visibility.Visible;
                HistoryTab.Visibility = Visibility.Visible;
            }
        }

        private void InitializeHistoryTab()
        {
            HistoryFromDate.Value = DateTime.Today.AddDays(-14).Date.ToShortDateString() + " " +
                                    DateTime.Now.ToShortTimeString();
            HistoryToDate.Value = DateTime.Now.ToShortDateString() + " " + DateTime.Now.ToShortTimeString();
            CmdletNameChanges.Value = "*";
            HistoryFromDate.IsReadOnly = false;
            HistoryToDate.IsReadOnly = false;
            CmdletNameChanges.IsReadOnly = false;
            JumpToSpecificPage.IsReadOnly = false;
        }

        private void LoadProjectUsers(String projectName)
        {
            List<PsSpecUserPermission> projectUsers = new List<PsSpecUserPermission>();
            projectUsers = GetUserList(projectName);
            UsersList.DataContext = projectUsers;
        }

        private void UpdateUIForRole()
        {
            // Customizations for project owners
            if (CmdletDesignerUtils.IsInRole(PsSpecProjectRole.ProjectOwner, Application.Current))
            {
                NounName.IsReadOnly = false;
                UserName.IsReadOnly = true;
                UserRole.IsReadOnly = true;
                UsersList.IsEnabled = true;
                NounDefinition.IsReadOnly = false;
            }

            // Customizations for spec writers
            if (CmdletDesignerUtils.IsInRole(PsSpecProjectRole.SpecWriter, Application.Current))
            {
            }

            // Customizations for help writers
            if (CmdletDesignerUtils.IsInRole(PsSpecProjectRole.HelpWriter, Application.Current))
            {
            }

            HistoryFromDate.IsEnabled = true;
            HistoryToDate.IsEnabled = true;
            ChangeType.IsEnabled = true;
            CmdletNameChanges.IsEnabled = true;
        }

        // Reload the list of cmdlets, keeping the sorting / filtering in the
        // collection view if possible
        private void ReloadCmdlets(PsSpecProject selectedProject)
        {
            if (CmdletCollectionView != null)
            {
                List<PsSpecCmdlet> cmdlets = CmdletCollectionView.SourceCollection as List<PsSpecCmdlet>;
                cmdlets.Clear();
                CmdletCollectionView.Refresh();
            }
            else
            {
                Cmdlets.DataContext = null;
            }

            BackgroundWorker worker = new BackgroundWorker();

            worker.DoWork += new DoWorkEventHandler(worker_LoadCmdlets);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_LoadCmdletsCompleted);

            Cursor = Cursors.Wait;
            worker.RunWorkerAsync(selectedProject.Name);
        }

        private void worker_LoadCmdletsCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Reload the cmdlets
            if (CmdletCollectionView != null)
            {
                List<PsSpecCmdlet> cmdlets = CmdletCollectionView.SourceCollection as List<PsSpecCmdlet>;
                cmdlets.Clear();
                cmdlets.AddRange(_backgroundLoadedCmdlets);
                CmdletCollectionView.Refresh();
            }
            else
            {
                Cmdlets.DataContext = null;
                Cmdlets.DataContext = _backgroundLoadedCmdlets;
            }

            Cursor = Cursors.Arrow;
        }

        private void worker_LoadCmdlets(object sender, DoWorkEventArgs e)
        {
            _backgroundLoadedCmdlets = GetCmdlets((string)e.Argument);
            e.Result = true;
        }

        // Resize the columns to fit when we resize the cmdlet
        // list
        private void Cmdlets_SizeOrDataChanged(Object sender, EventArgs e)
        {
            CmdletDesignerUtils.ResizeColumns(Cmdlets, "Short Description");
            ICollectionView collectionView = CmdletCollectionView;
            if (collectionView != null)
            {
                collectionView.Refresh();
            }
        }

        // They've double clicked on a cmdlet
        private void DoubleClick_SelectCmdlet(Object sender, MouseButtonEventArgs e)
        {
            EditCmdlet();
        }

        // They've clicked "Edit Cmdlet"
        private void Click_EditCmdlet(Object sender, RoutedEventArgs e)
        {
            EditCmdlet();
        }


        // They've clicked "Add Noun"
        private void Click_AddNoun(Object sender, RoutedEventArgs e)
        {
            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];

            if (selectedProject == null)
            {
                MessageBox.Show("Please select a project.");
                return;
            }

            // Create the Add-PsSpecNoun dialog
            AddNoun addNounDialog = new AddNoun(this);

            if ((bool)addNounDialog.ShowDialog())
            {
                if (addNounDialog.NounNameText == null)
                {
                    MessageBox.Show("Please enter a noun name.");
                    return;
                }

                if (addNounDialog.NounDefinitionText == null)
                {
                    MessageBox.Show("Please enter a noun definition.");
                    return;
                }

                // New-PsSpecNoun -Name <Name> -Definition <Definition> -ProjectName <Project>
                NewPsSpecNounCommand command = new NewPsSpecNounCommand();
                command.Name = addNounDialog.NounNameText;
                command.Definition = addNounDialog.NounDefinitionText;
                command.ProjectName = selectedProject.Name;
                command.ServiceUri = ServiceUri;

                try
                {
                    command.Invoke().GetEnumerator().MoveNext();
                }
                catch (Exception exception)
                {
                    CmdletDesignerUtils.HandleException("Error creating noun",
                                                        "There were errors creating a noun.",
                                                        exception);
                }

                // Refresh the verbs and nouns list
                PopulateVerbsAndNouns(true);
            }
        }

        // They've clicked "Delete Noun"
        private void Click_DeleteNoun(Object sender, RoutedEventArgs e)
        {
            PsSpecNoun selectedNoun = NounList.SelectedItem as PsSpecNoun;

            MessageBoxResult result = MessageBox.Show(
                "Are you sure you wish to delete the '" + selectedNoun.Name + "' noun?",
                "Delete this noun?",
                MessageBoxButton.YesNo);
            if (result != MessageBoxResult.Yes)
                return;

            // $currentNoun | Remove-PsSpecNoun -Force
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                Command deleteCommand = new Command("Remove-PsSpecNoun");
                deleteCommand.Parameters.Add("ServiceUri", ServiceUri);
                deleteCommand.Parameters.Add("Force");

                pipeline.Input.Write(selectedNoun);
                pipeline.Commands.Add(deleteCommand);

                Collection<PSObject> results = pipeline.Invoke();
                HandleErrors(pipeline);
            }

            // Refresh the verbs and nouns list
            PopulateVerbsAndNouns(true);
        }

        // They've clicked "Add Cmdlet"
        private void Click_AddCmdlet(Object sender, RoutedEventArgs e)
        {
            AddCmdlet(false);
        }

        // They've clicked "Delete Cmdlet"
        private void Click_DeleteCmdlet(Object sender, RoutedEventArgs e)
        {
            PsSpecCmdlet selectedCmdlet = Cmdlets.SelectedItem as PsSpecCmdlet;
            if (selectedCmdlet == null)
            {
                MessageBox.Show("Please select a cmdlet.");
                return;
            }

            MessageBoxResult result = MessageBox.Show(
                "Are you sure you wish to delete the '" + GetName(selectedCmdlet) + "' cmdlet?",
                "Delete this cmdlet?",
                MessageBoxButton.YesNo);
            if (result != MessageBoxResult.Yes)
                return;

            // $currentCmdlet | Remove-PsSpecCmdlet -Force
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                Command deleteCommand = new Command("Remove-PsSpecCmdlet");
                deleteCommand.Parameters.Add("ServiceUri", ServiceUri);
                deleteCommand.Parameters.Add("Force");

                pipeline.Input.Write(selectedCmdlet);
                pipeline.Commands.Add(deleteCommand);

                Collection<PSObject> results = pipeline.Invoke();
                HandleErrors(pipeline);
            }

            // Refresh the cmdlet list
            PsSpecCmdlet currentCmdlet = CmdletSummaryContent.DataContext as PsSpecCmdlet;
            if ((currentCmdlet != null) &&
                (currentCmdlet.Verb == selectedCmdlet.Verb) &&
                (currentCmdlet.Noun == selectedCmdlet.Noun))
            {
                Application.Current.Properties["OriginalCmdlet"] = null;
                CmdletTab.Visibility = Visibility.Collapsed;
            }

            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];
            ReloadCmdlets(selectedProject);
        }

        // They've clicked "Clone Cmdlet"
        private void Click_CloneCmdlet(Object sender, RoutedEventArgs e)
        {
            AddCmdlet(true);
        }

        private void AddCmdlet(bool fromSelectedCmdlet)
        {
            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];

            if (selectedProject == null)
            {
                MessageBox.Show("Please select a project.");
                return;
            }

            AddCmdlet addCmdletDialog = new AddCmdlet(this);

            addCmdletDialog.Verb.DataContext = _verbList;
            addCmdletDialog.Noun.DataContext = _nounList;

            // If they wanted to clone an existing cmdlet,
            // then select that one automatically.
            if (fromSelectedCmdlet)
            {
                addCmdletDialog.CmdletList.SelectedItem = Cmdlets.SelectedItem;
            }

            // Populate the list of cmdlets from their project
            List<PsSpecCmdlet> selectionList = new List<PsSpecCmdlet>();
            foreach (PsSpecCmdlet current in Cmdlets.ItemsSource)
            {
                selectionList.Add(current);
            }
            addCmdletDialog.CmdletList.DataContext = selectionList;

            if ((bool)addCmdletDialog.ShowDialog())
            {
                if (addCmdletDialog.VerbName == null)
                {
                    MessageBox.Show("Please provide a verb name.");
                    return;
                }
                if (addCmdletDialog.NounName == null)
                {
                    MessageBox.Show("Please provide a noun name.");
                    return;
                }

                if (addCmdletDialog.CmdletList.SelectedItem == null)
                {
                    CreateNewCmdlet(selectedProject, addCmdletDialog);
                }
                else
                {
                    CreateAndCloneCmdlet(selectedProject, addCmdletDialog);
                }

                ReloadCmdlets(selectedProject);

                // And then go to the "select a cmdlet" tab
                NavigationTabs.SelectedItem = CmdletsListTab;
            }
        }

        private void CreateNewCmdlet(PsSpecProject selectedProject, AddCmdlet addCmdletDialog)
        {
            // New-PsSpecCmdlet -ProjectName <Project> -Verb <Verb> -Noun <Noun>
            NewPsSpecCmdletCommand command = new NewPsSpecCmdletCommand();
            command.ProjectName = selectedProject.Name;
            command.Verb = addCmdletDialog.VerbName;
            command.Noun = addCmdletDialog.NounName;
            command.ServiceUri = ServiceUri;

            try
            {
                command.Invoke().GetEnumerator().MoveNext();
            }
            catch (Exception exception)
            {
                CmdletDesignerUtils.HandleException("Error creating cmdlet",
                                                    "There were errors creating a cmdlet.",
                                                    exception);
            }
        }

        private void CreateAndCloneCmdlet(PsSpecProject selectedProject, AddCmdlet addCmdletDialog)
        {
            PsSpecCmdlet otherCmdlet = addCmdletDialog.CmdletList.SelectedItem as PsSpecCmdlet;
            string otherCmdletName = GetName(otherCmdlet);

            Collection<PSObject> parameters = null;
            Collection<PSObject> parameterSetEntries = null;

            // $otherCmdlet | New-PsSpecCmdlet -Verb <Verb> -Noun <Noun> -Service $serviceUri
            PsSpecCmdlet newCmdlet = null;
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                // Create the new cmdlet
                Command newCommand = new Command("New-PsSpecCmdlet");
                newCommand.Parameters.Add("Verb", addCmdletDialog.VerbName);
                newCommand.Parameters.Add("Noun", addCmdletDialog.NounName);
                newCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Input.Write(otherCmdlet);
                pipeline.Commands.Add(newCommand);

                foreach (PSObject current in pipeline.Invoke())
                {
                    newCmdlet = (PsSpecCmdlet)current.BaseObject;
                }
                HandleErrors(pipeline);
            }

            if (newCmdlet == null)
                return;


            // $parameters = $oldCmdlet | Get-PsSpecCmdletParameter -Service $serviceUri
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                // Get the parameters
                Command getCommand = new Command("Get-PsSpecCmdletParameter");
                getCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Input.Write(otherCmdlet);
                pipeline.Commands.Add(getCommand);

                parameters = pipeline.Invoke();
                HandleErrors(pipeline);
            }

            if (parameters.Count == 0)
                return;

            // $parameters | Add-PsSpecCmdletParameter -CmdletName <CmdletName> -Service $serviceUri
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                // Create the new cmdlet
                Command newCommand = new Command("Add-PsSpecCmdletParameter");
                newCommand.Parameters.Add("CmdletName", GetName(newCmdlet));
                newCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Input.Write(parameters, true);
                pipeline.Commands.Add(newCommand);

                Collection<PSObject> results = pipeline.Invoke();
                HandleErrors(pipeline);
            }

            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                // Remove the old temporary default parameter set entry
                Command getCommand = new Command("Get-PsSpecCmdletParameterSetEntry");
                getCommand.Parameters.Add("ProjectName", newCmdlet.ProjectName);
                getCommand.Parameters.Add("CmdletName", GetName(newCmdlet));
                getCommand.Parameters.Add("ServiceUri", ServiceUri);

                Command removeCommand = new Command("Remove-PsSpecCmdletParameterSetEntry");
                removeCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Commands.Add(getCommand);
                pipeline.Commands.Add(removeCommand);

                Collection<PSObject> results = pipeline.Invoke();
                HandleErrors(pipeline);
            }

            // $parameterSetEntries = Get-PsSpecCmdletParameterSetEntry -CmdletName $otherCmdletName
            //                              -Service $serviceUri
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                // Get the parameter set entries
                Command getCommand = new Command("Get-PsSpecCmdletParameterSetEntry");
                getCommand.Parameters.Add("CmdletName", otherCmdletName);
                getCommand.Parameters.Add("ProjectName", otherCmdlet.ProjectName);
                getCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Commands.Add(getCommand);

                parameterSetEntries = pipeline.Invoke();
                HandleErrors(pipeline);
            }

            if (parameterSetEntries.Count == 0)
                return;

            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                // Copy the parameter set entries
                Command addCommand = new Command("Add-PsSpecCmdletParameterSetEntry");
                addCommand.Parameters.Add("CmdletName", GetName(newCmdlet));
                addCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Commands.Add(addCommand);

                pipeline.Input.Write(parameterSetEntries, true);
                Collection<PSObject> results = pipeline.Invoke();
                HandleErrors(pipeline);
            }
        }

        // Edit a given cmdlet -- select the cmdlet tab, and set the
        // summary header
        private void EditCmdlet()
        {
            if (Cmdlets.SelectedItems.Count > 0)
            {
                if (HasUnsavedChanges())
                    return;

                PopulateCmdletData((PsSpecCmdlet)Cmdlets.SelectedItem, false);

                // Make the tab visible
                CmdletTab.Visibility = Visibility.Visible;

                NavigationTabs.SelectedItem = CmdletTab;
                SelectCmdletRegion(CmdletSummaryContent);
            }

            Cursor = Cursors.Arrow;
        }


        // Populates all the information about a cmdlet into the
        // application
        private void PopulateCmdletData(PsSpecCmdlet cmdlet, bool bypassWarning)
        {
            if (cmdlet == null)
                cmdlet = (PsSpecCmdlet)Cmdlets.SelectedItem;

            if (cmdlet != null)
            {
                // Poupulate the information in the cmdlet tab
                PopulateCmdlet(cmdlet);

                // Populate the information into the parameters tab
                PopulateParameters(cmdlet);
            }
        }

        // Populate the information related to the cmdlet itself
        private void PopulateCmdlet(PsSpecCmdlet current)
        {
            PsSpecCmdlet original = (PsSpecCmdlet)current.Clone();
            Application.Current.Properties["OriginalCmdlet"] = original;

            // Populate the information into the summary,
            // details, specExamples tabs
            CmdletSummaryContent.DataContext = null;
            CmdletDetailsContent.DataContext = null;
            SpecExamplesContent.DataContext = null;
            CmdletSummaryContent.DataContext = current;
            CmdletDetailsContent.DataContext = current;
            SpecExamplesContent.DataContext = current;

            // Update the cmdlet header
            CmdletTab.Header = current.Verb + "-" + current.Noun;
            Title = CmdletTab.Header +
                    " (" + current.ProjectName + " Spec Project) - PowerShell Cmdlet Designer";
        }

        // Refresh the verbs and nouns list
        private void PopulateVerbsAndNouns(bool forceRefresh)
        {
            // Populate the list of verbs
            if (_verbList == null)
            {
                _verbList = GetVerbs();

                CmdletSummaryContent.Verb.Items.DataContext = null;
                CmdletSummaryContent.Verb.Items.DataContext = _verbList;
            }

            // Populate the list of nouns
            if (forceRefresh || (_nounList == null))
            {
                _nounList = GetNouns();
                List<PsSpecNoun> originalNouns = new List<PsSpecNoun>();

                // Save the original nouns, so that we can detect
                // modifications later
                foreach (PsSpecNoun noun in _nounList)
                {
                    originalNouns.Add((PsSpecNoun)noun.Clone());
                }

                Application.Current.Properties["OriginalNouns"] = originalNouns;

                NounList.DataContext = null;
                NounList.DataContext = _nounList;
                NounList.SelectedIndex = 0;

                // Restore the selected noun in their cmdlet since we just refreshed
                // the noun list
                string selectedNoun = CmdletSummaryContent.Noun.SelectedValue;

                // Refresh the nouns attached to the open cmdlet
                CmdletSummaryContent.Noun.Items.DataContext = null;
                CmdletSummaryContent.Noun.Items.DataContext = _nounList;

                // If they had a noun selected, re-select it
                if (selectedNoun != null)
                {
                    CmdletSummaryContent.Noun.SelectedValue = selectedNoun;
                }
            }
        }

        // Get the friendly name for a cmdlet
        private string GetName(PsSpecCmdlet cmdlet)
        {
            return cmdlet.Verb + "-" + cmdlet.Noun;
        }

        // Populate the parameter set entries for a cmdlet
        private void PopulateParameterEntries(PsSpecCmdlet current)
        {
            List<PsSpecCmdletParameterSetEntry> parameterEntries = GetParameterEntries(GetName(current),
                                                                                       current.ProjectName);
            List<PsSpecCmdletParameterSetEntry> originalParameterEntries = new List<PsSpecCmdletParameterSetEntry>();

            // Store these entries away, so that we can detect modifications later
            foreach (PsSpecCmdletParameterSetEntry parameterEntry in parameterEntries)
            {
                originalParameterEntries.Add((PsSpecCmdletParameterSetEntry)parameterEntry.Clone());
            }

            Application.Current.Properties["OriginalParameterEntries"] = originalParameterEntries;

            // If the view is already set up for this, just update the items. We do this
            // so that we don't trash the sorting / filtering attached to the view
            ICollectionView view =
                CollectionViewSource.GetDefaultView(PsSpecCmdletParameterEntriesContent.DataContext);
            if (view != null)
            {
                List<PsSpecCmdletParameterSetEntry> collectionParameters =
                    (List<PsSpecCmdletParameterSetEntry>)view.SourceCollection;
                collectionParameters.Clear();
                collectionParameters.AddRange(parameterEntries);
            }
            else
            {
                // Otherwise, set these as the data context
                PsSpecCmdletParameterEntriesContent.DataContext = parameterEntries;

                // Set the parameter set view to sort by ParameterSetName
                view = CollectionViewSource.GetDefaultView(PsSpecCmdletParameterEntriesContent.DataContext);
                view.GroupDescriptions.Clear();
                view.GroupDescriptions.Add(new PropertyGroupDescription("ParameterSetName"));
            }
        }


        private void PopulateParameters(PsSpecCmdlet current)
        {
            int selectedParameterIndex = ParameterSelector.SelectedIndex;
            List<PsSpecCmdletParameter> parameters = GetParameters(GetName(current), current.ProjectName);
            List<PsSpecCmdletParameter> originalParameters = new List<PsSpecCmdletParameter>();
            // Get the parameter entries
            PopulateParameterEntries(current);
            List<PsSpecCmdletParameterSetEntry> parameterEntries =
                (List<PsSpecCmdletParameterSetEntry>)PsSpecCmdletParameterEntriesContent.DataContext;

            // Prepare the parameter details view for binding
            List<PsSpecCmdletParameterDetails> parameterDetails = new List<PsSpecCmdletParameterDetails>();
            List<PsSpecCmdletParameterDetails> firstParameterDetailsItem = new List<PsSpecCmdletParameterDetails>();

            // Go through each parameter to save the original version, and
            // create the merged parameter entry view.
            foreach (PsSpecCmdletParameter parameter in parameters)
            {
                originalParameters.Add((PsSpecCmdletParameter)parameter.Clone());
                parameterDetails.Add(new PsSpecCmdletParameterDetails(parameter, parameterEntries));
            }

            // Store these original parameters so that we can detect changes
            // to them later.
            Application.Current.Properties["OriginalParameters"] = originalParameters;
            if (parameterDetails.Count > 0)
            {
                firstParameterDetailsItem.Add(parameterDetails[0]);
            }
            // Clear the old data context elements
            PsSpecCmdletParametersContent.DataContext = null;
            PsSpecCmdletParametersContent.DataContext = firstParameterDetailsItem;
            ParameterSelector.DataContext = null;
            ParameterSelector.DataContext = parameterDetails;
            _parameterCollectionView = null;
            ParameterSelector.SelectedIndex = selectedParameterIndex;

            RefreshDataContext(PsSpecCmdletParametersContent);
        }

        // They've clicked on the summary header
        private void Click_Summary(Object sender, RoutedEventArgs e)
        {
            SelectCmdletRegion(CmdletSummaryContent);
        }

        // They've clicked on the details header
        private void Click_Details(Object sender, RoutedEventArgs e)
        {
            SelectCmdletRegion(CmdletDetailsContent);
        }

        // They've clicked on the spec examples header
        private void Click_SpecExamples(Object sender, RoutedEventArgs e)
        {
            SelectCmdletRegion(SpecExamplesContent);
        }

        // They've clicked on the parameters header
        private void Click_Parameters(Object sender, RoutedEventArgs e)
        {
            SelectCmdletRegion(PsSpecCmdletParametersContent);
        }


        // They've clicked on the "new parameter" button
        private void Click_NewParameter(Object sender, RoutedEventArgs e)
        {
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;

            if (current == null)
            {
                MessageBox.Show("Please select a cmdlet.");
                return;
            }

            AddParameter addParameterDialog = new AddParameter(this);
            if ((bool)addParameterDialog.ShowDialog())
            {
                // Add-PsSpecCmdletParameter -ProjectName <project> -CmdletName <Cmdlet>
                //                     -Name <ParameterName> -Type <ParameterType>
                AddPsSpecCmdletParameterCommand command = new AddPsSpecCmdletParameterCommand();
                command.ProjectName = current.ProjectName;
                command.CmdletName = GetName(current);
                command.Name = addParameterDialog.ParameterNameText;
                command.Type = addParameterDialog.ParameterTypeText;
                command.ServiceUri = ServiceUri;

                try
                {
                    command.Invoke().GetEnumerator().MoveNext();
                }
                catch (Exception exception)
                {
                    CmdletDesignerUtils.HandleException("Error creating parameter",
                                                        "There were errors creating a parameter.",
                                                        exception);
                }

                if (HasChangedParameter() || HasChangedParameterEntry())
                {
                    string message = "You have unsaved changes. Do you want to save the change before " +
                                     "reloading this cmdlet's parameters?";

                    MessageBoxResult result = MessageBox.Show(message,
                                                              "You have unsaved changes.", MessageBoxButton.YesNoCancel);

                    if (result == MessageBoxResult.Yes)
                    {
                        bool saveSuccessful = SaveChanges(false);

                        if (!saveSuccessful)
                        {
                            return;
                        }
                    }
                    else if (result == MessageBoxResult.Cancel)
                    {
                        return;
                    }
                }

                PopulateParameters(current);
                SelectCmdletRegion(PsSpecCmdletParametersContent);
            }
        }

        // They've clicked "Delete Parameter"
        private void Click_DeleteParameter(Object sender, RoutedEventArgs e)
        {
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;

            if (current == null)
            {
                MessageBox.Show("Please select a cmdlet.");
                return;
            }

            // See if they want to save their changes
            if (HasChangedParameter() || HasChangedParameterEntry())
            {
                string message = "You have unsaved changes. Do you want to save the change before " +
                                 "managing (and then reloading) this cmdlet's parameters?";

                MessageBoxResult unsaveChangesResult = MessageBox.Show(message,
                                                                       "You have unsaved changes.",
                                                                       MessageBoxButton.YesNoCancel);

                if (unsaveChangesResult == MessageBoxResult.Yes)
                {
                    bool saveSuccessful = SaveChanges(false);

                    if (!saveSuccessful)
                    {
                        return;
                    }
                }
                else if (unsaveChangesResult == MessageBoxResult.Cancel)
                {
                    return;
                }
            }

            // Go through the selected parameters and delete them
            bool madeChange = false;

            PsSpecCmdletParameterDetails selectedParam =
                (PsSpecCmdletParameterDetails)ParameterSelector.Items[ParameterSelector.SelectedIndex];
            String name = selectedParam.Name;

            MessageBoxResult result = MessageBox.Show(
                "Are you sure you wish the '" + name + "' parameter deleted?",
                "Delete this parameter?",
                MessageBoxButton.YesNoCancel);


            if (result == MessageBoxResult.Yes)
            {
                // $currentParameter | Remove-PsSpecCmdletParameter
                using (Pipeline pipeline = _runspace.CreatePipeline())
                {
                    Command deleteCommand = new Command("Remove-PsSpecCmdletParameter");
                    deleteCommand.Parameters.Add("ServiceUri", ServiceUri);

                    pipeline.Input.Write(selectedParam);
                    pipeline.Commands.Add(deleteCommand);

                    Collection<PSObject> results = pipeline.Invoke();
                    HandleErrors(pipeline);

                    madeChange = true;
                }

                if (madeChange)
                {
                    // Reload the cmdlet
                    PopulateParameters(current);
                    SelectCmdletRegion(PsSpecCmdletParametersContent);
                }
            }
        }

        // They've clicked on the "import parameter" button
        private void Click_ImportParameter(Object sender, RoutedEventArgs e)
        {
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;

            if (current == null)
            {
                MessageBox.Show("Please select a cmdlet.");
                return;
            }

            ImportParameter importParameterDialog = new ImportParameter(current.ProjectName, ServiceUri.ToString(), this);
            if ((bool)importParameterDialog.ShowDialog())
            {
                // Get all of the parameters they selected
                ObservableCollection<PsSpecCmdletParameterGroupEntry> selectedParameters =
                    importParameterDialog.SelectedParameters;

                foreach (PsSpecCmdletParameterGroupEntry groupEntry in selectedParameters)
                {
                    using (Pipeline pipeline = _runspace.CreatePipeline())
                    {
                        // Get the first parameter that matches the given
                        // name, type, and description
                        Command getParameterCommand = new Command("Get-PsSpecCmdletParameter");
                        getParameterCommand.Parameters.Add("Name", groupEntry.ParameterName);
                        getParameterCommand.Parameters.Add("Type", groupEntry.Type);
                        getParameterCommand.Parameters.Add("Description", groupEntry.Description);
                        getParameterCommand.Parameters.Add("ServiceUri", ServiceUri);

                        Command selectCommand = new Command("Select-Object");
                        selectCommand.Parameters.Add("First", 1);

                        // $foundParameter | Add-PsSpecCmdletParameter
                        Command addCommand = new Command("Add-PsSpecCmdletParameter");
                        addCommand.Parameters.Add("ProjectName", current.ProjectName);
                        addCommand.Parameters.Add("CmdletName", GetName(current));
                        addCommand.Parameters.Add("ServiceUri", ServiceUri);

                        pipeline.Commands.Add(getParameterCommand);
                        pipeline.Commands.Add(selectCommand);
                        pipeline.Commands.Add(addCommand);

                        Collection<PSObject> results = pipeline.Invoke();
                        HandleErrors(pipeline);
                    }

                    using (Pipeline pipeline = _runspace.CreatePipeline())
                    {
                        // Remove the old temporary default parameter set entry
                        Command getCommand = new Command("Get-PsSpecCmdletParameterSetEntry");
                        getCommand.Parameters.Add("ParameterName", groupEntry.ParameterName);
                        getCommand.Parameters.Add("ProjectName", current.ProjectName);
                        getCommand.Parameters.Add("CmdletName", GetName(current));
                        getCommand.Parameters.Add("ServiceUri", ServiceUri);

                        Command removeCommand = new Command("Remove-PsSpecCmdletParameterSetEntry");
                        removeCommand.Parameters.Add("ServiceUri", ServiceUri);

                        pipeline.Commands.Add(getCommand);
                        pipeline.Commands.Add(removeCommand);

                        Collection<PSObject> results = pipeline.Invoke();
                        HandleErrors(pipeline);
                    }

                    using (Pipeline pipeline = _runspace.CreatePipeline())
                    {
                        // Copy the parameter set entries
                        Command getParameterCommand = new Command("Get-PsSpecCmdletParameter");
                        getParameterCommand.Parameters.Add("Name", groupEntry.ParameterName);
                        getParameterCommand.Parameters.Add("Type", groupEntry.Type);
                        getParameterCommand.Parameters.Add("Description", groupEntry.Description);
                        getParameterCommand.Parameters.Add("ServiceUri", ServiceUri);

                        Command selectCommand = new Command("Select-Object");
                        selectCommand.Parameters.Add("First", 1);

                        Command getParameterSetCommand = new Command("Get-PsSpecCmdletParameterSetEntry");
                        getParameterSetCommand.Parameters.Add("ParameterName", groupEntry.ParameterName);
                        getParameterSetCommand.Parameters.Add("ServiceUri", ServiceUri);

                        Command addCommand = new Command("Add-PsSpecCmdletParameterSetEntry");
                        addCommand.Parameters.Add("ProjectName", current.ProjectName);
                        addCommand.Parameters.Add("CmdletName", GetName(current));
                        addCommand.Parameters.Add("ServiceUri", ServiceUri);

                        pipeline.Commands.Add(getParameterCommand);
                        pipeline.Commands.Add(selectCommand);
                        pipeline.Commands.Add(getParameterSetCommand);
                        pipeline.Commands.Add(addCommand);

                        Collection<PSObject> results = pipeline.Invoke();
                        HandleErrors(pipeline);
                    }
                }

                if (HasChangedParameter() || HasChangedParameterEntry())
                {
                    string message = "You have unsaved changes. Do you want to save the change before " +
                                     "reloading this cmdlet's parameters?";

                    MessageBoxResult result = MessageBox.Show(message,
                                                              "You have unsaved changes.", MessageBoxButton.YesNoCancel);

                    if (result == MessageBoxResult.Yes)
                    {
                        bool saveSuccessful = SaveChanges(false);

                        if (!saveSuccessful)
                        {
                            return;
                        }
                    }
                    else if (result == MessageBoxResult.Cancel)
                    {
                        return;
                    }
                }

                PopulateParameters(current);
                SelectCmdletRegion(PsSpecCmdletParametersContent);
            }
        }

        // They've clicked on the parameter set entries header
        private void Click_ParameterEntries(Object sender, RoutedEventArgs e)
        {
            RefreshDataContext(PsSpecCmdletParameterEntriesContent);
            SelectCmdletRegion(PsSpecCmdletParameterEntriesContent);
        }

        // They've clicked on the spec view entries header
        private void Click_SpecView(Object sender, RoutedEventArgs e)
        {
            BackgroundWorker worker = new BackgroundWorker();

            // Get the currently open cmdlet
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;
            worker.DoWork += new DoWorkEventHandler(worker_GenerateCmdletSpec);
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_GenerateCmdletSpecCompleted);

            Cursor = Cursors.Wait;
            worker.RunWorkerAsync(current);
        }

        private void worker_GenerateCmdletSpec(object sender, DoWorkEventArgs e)
        {
            PsSpecCmdlet current = e.Argument as PsSpecCmdlet;
            _backgroundStringOutput = GenerateSpecViewData(current);
        }

        private void worker_GenerateCmdletSpecCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            HtmlViewWindow htmlView = new HtmlViewWindow(_backgroundStringOutput, this);
            htmlView.Show();

            Cursor = Cursors.Arrow;
        }

        // They've clicked on the cmdlet generator header
        private void Click_CmdletGenerator(Object sender, RoutedEventArgs e)
        {
            // Get the currently open cmdlet
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;

            if (current == null)
                return;

            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                string commandPath = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                    "Get-CmdletTemplate.ps1");

                Command reportCommand = new Command(commandPath);
                reportCommand.Parameters.Add("CmdletName", GetName(current));
                reportCommand.Parameters.Add("ProjectName", current.ProjectName);
                reportCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Commands.Add(reportCommand);

                Collection<PSObject> results;

                try
                {
                    results = pipeline.Invoke();
                }
                catch (Exception exception)
                {
                    CmdletDesignerUtils.HandleException("Error generating spec",
                                                        "There were errors generating the spec.",
                                                        exception);

                    return;
                }

                HandleErrors(pipeline);

                string output = "<pre>";

                foreach (PSObject result in results)
                    output += "\n" + HttpUtility.HtmlEncode((string)result.BaseObject);

                output += "</pre>";

                HtmlViewWindow htmlView = new HtmlViewWindow(output, this);
                htmlView.Show();
            }
        }

        // They've clicked on the MAML generator header
        private void Click_HelpGenerator(Object sender, RoutedEventArgs e)
        {
            // Get the currently open cmdlet
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;

            if (current == null)
                return;

            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                string commandPath = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                    "Get-SpecMaml.ps1");

                Command reportCommand = new Command(commandPath);
                reportCommand.Parameters.Add("CmdletName", GetName(current));
                reportCommand.Parameters.Add("ProjectName", current.ProjectName);
                reportCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Commands.Add(reportCommand);

                Collection<PSObject> results;

                try
                {
                    results = pipeline.Invoke();
                }
                catch (Exception exception)
                {
                    CmdletDesignerUtils.HandleException("Error generating spec",
                                                        "There were errors generating the spec.",
                                                        exception);

                    return;
                }

                HandleErrors(pipeline);

                string output = "<pre>";

                foreach (PSObject result in results)
                    output += "\n" + HttpUtility.HtmlEncode((string)result.BaseObject);

                output += "</pre>";

                HtmlViewWindow htmlView = new HtmlViewWindow(output, this);
                htmlView.Show();
            }
        }

        // They've changed the parameter search text
        private void ParameterSearch_TextChanged(Object sender, TextChangedEventArgs e)
        {
            if (ParameterSelector != null)
            {
                ICollectionView collectionView = ParameterCollectionView;
                if (collectionView != null)
                {
                    collectionView.Refresh();
                }
            }
        }


        // They focused on the parameter search box
        private void ParameterSearch_GotFocus(Object sender, EventArgs e)
        {
            // Ensure the parameters are visible
            SelectCmdletRegion(PsSpecCmdletParametersContent);
            ActivateSearchField(ParameterSearch);
        }

        // They've left the parameter search box
        private void ParameterSearch_LostFocus(Object sender, EventArgs e)
        {
            DeactivateSearchField(ParameterSearch);
        }

        // They've changed the cmdlet search text
        private void CmdletSearch_TextChanged(Object sender, TextChangedEventArgs e)
        {
            if (Cmdlets != null)
            {
                ICollectionView collectionView = CmdletCollectionView;
                if (collectionView != null)
                {
                    collectionView.Refresh();
                }
            }
        }

        // They focused on the cmdlet search box
        private void CmdletSearch_GotFocus(Object sender, EventArgs e)
        {
            ActivateSearchField(CmdletSearch);
        }

        // They've left the cmdlet search box
        private void CmdletSearch_LostFocus(Object sender, EventArgs e)
        {
            DeactivateSearchField(CmdletSearch);
        }

        // They've clicked on a column header of the cmdlets list
        private void Click_CmdletsColumnHeader(Object sender, RoutedEventArgs e)
        {
            GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
            ListSortDirection direction;

            // If they've never clicked on a header before, toggle the state of the
            // first header item
            if (_lastCmdletHeaderClicked == null)
            {
                _lastCmdletHeaderClicked = (GridViewColumnHeader)CmdletsView.Columns[0].Header;
            }

            if (headerClicked != null)
            {
                if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
                {
                    // Determine if they've clicked on a new header
                    if (headerClicked != _lastCmdletHeaderClicked)
                    {
                        direction = ListSortDirection.Ascending;
                    }
                    else
                    {
                        // Otherwise, flip the sort direction
                        if (_lastCmdletDirection == ListSortDirection.Ascending)
                        {
                            direction = ListSortDirection.Descending;
                        }
                        else
                        {
                            direction = ListSortDirection.Ascending;
                        }
                    }

                    // Get the header that represents the column they clicked on.
                    // We also remove spaces from the header text, as we actually need to sort on
                    // a property. This assumes that properties such as ShortDescription get expanded
                    // to "Short Description" in the header title.
                    string header = ((GridViewColumnHeader)headerClicked.Column.Header).Content as String;
                    header = header.Replace(" ", "");

                    // Clear the old sort descriptions, update it with new ones, and refresh the view
                    CmdletCollectionView.SortDescriptions.Clear();
                    SortDescription sd = new SortDescription(header, direction);
                    CmdletCollectionView.SortDescriptions.Add(sd);
                    CmdletCollectionView.Refresh();

                    // Apply the propert up / down arrow template to the column
                    if (direction == ListSortDirection.Ascending)
                    {
                        headerClicked.Column.HeaderTemplate =
                            Resources["HeaderTemplateArrowUp"] as DataTemplate;
                    }
                    else
                    {
                        headerClicked.Column.HeaderTemplate =
                            Resources["HeaderTemplateArrowDown"] as DataTemplate;
                    }

                    // Remove arrow from previously sorted header
                    if (_lastCmdletHeaderClicked != headerClicked)
                    {
                        _lastCmdletHeaderClicked.Column.HeaderTemplate = null;
                    }

                    // Remember what column they last clicked on (and sort direction)
                    // for future clicks
                    _lastCmdletHeaderClicked = headerClicked;
                    _lastCmdletDirection = direction;
                }
            }
        }

        // Resize the columns to fit when we resize the cmdlet
        // list
        private void Projects_SizeOrDataChanged(Object sender, EventArgs e)
        {
            CmdletDesignerUtils.ResizeColumns(Projects, "Description");
            ICollectionView collectionView = ProjectCollectionView;
            if (collectionView != null)
            {
                collectionView.Refresh();
            }
        }

        // They've changed the cmdlet search text
        private void ProjectSearch_TextChanged(Object sender, TextChangedEventArgs textChangedEventArgs)
        {
            if (Projects != null)
            {
                ICollectionView collectionView = ProjectCollectionView;
                if (collectionView != null)
                {
                    collectionView.Refresh();
                }
            }
        }

        // They focused on the cmdlet search box
        private void ProjectSearch_GotFocus(Object sender, EventArgs e)
        {
            ActivateSearchField(ProjectSearch);
        }

        // They've left the cmdlet search box
        private void ProjectSearch_LostFocus(Object sender, EventArgs e)
        {
            DeactivateSearchField(ProjectSearch);
        }

        // They've clicked on a column header of the cmdlets list
        private void Click_ProjectsColumnHeader(Object sender, RoutedEventArgs e)
        {
            GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader;
            ListSortDirection direction;

            // If they've never clicked on a header before, toggle the state of the
            // first header item
            if (_lastProjectHeaderClicked == null)
            {
                _lastProjectHeaderClicked = (GridViewColumnHeader)ProjectsView.Columns[0].Header;
            }

            if (headerClicked != null)
            {
                if (headerClicked.Role != GridViewColumnHeaderRole.Padding)
                {
                    // Determine if they've clicked on a new header
                    if (headerClicked != _lastProjectHeaderClicked)
                    {
                        direction = ListSortDirection.Ascending;
                    }
                    else
                    {
                        // Otherwise, flip the sort direction
                        if (_lastProjectDirection == ListSortDirection.Ascending)
                        {
                            direction = ListSortDirection.Descending;
                        }
                        else
                        {
                            direction = ListSortDirection.Ascending;
                        }
                    }

                    // Get the header that represents the column they clicked on.
                    // We also remove spaces from the header text, as we actually need to sort on
                    // a property. This assumes that properties such as ShortDescription get expanded
                    // to "Short Description" in the header title.
                    string header = ((GridViewColumnHeader)headerClicked.Column.Header).Content as String;
                    header = header.Replace(" ", "");

                    // Clear the old sort descriptions, update it with new ones, and refresh the view

                    ProjectCollectionView.SortDescriptions.Clear();
                    SortDescription sd = new SortDescription(header, direction);
                    ProjectCollectionView.SortDescriptions.Add(sd);
                    ProjectCollectionView.Refresh();

                    // Apply the propert up / down arrow template to the column
                    if (direction == ListSortDirection.Ascending)
                    {
                        headerClicked.Column.HeaderTemplate =
                            Resources["HeaderTemplateArrowUp"] as DataTemplate;
                    }
                    else
                    {
                        headerClicked.Column.HeaderTemplate =
                            Resources["HeaderTemplateArrowDown"] as DataTemplate;
                    }

                    // Remove arrow from previously sorted header
                    if (_lastProjectHeaderClicked != headerClicked)
                    {
                        _lastProjectHeaderClicked.Column.HeaderTemplate = null;
                    }

                    // Remember what column they last clicked on (and sort direction)
                    // for future clicks
                    _lastProjectHeaderClicked = headerClicked;
                    _lastProjectDirection = direction;
                }
            }
        }

        // Activate a search field when somebody enters it.
        private void ActivateSearchField(TextBox searchBox)
        {
            searchBox.Foreground = Brushes.Black;

            if (searchBox.Text == "Search")
            {
                searchBox.Text = "";
            }
        }

        // Convert the search field back to its inactive state
        private void DeactivateSearchField(TextBox searchBox)
        {
            searchBox.Foreground = new SolidColorBrush(Color.FromArgb(128, 0, 0, 0));

            if (String.IsNullOrEmpty(searchBox.Text) || (searchBox.Text == "Search"))
            {
                searchBox.Text = "Search";
            }
        }

        // The collection view that supports the parameter filtering and sorting

        // They've clicked on an item in the search results
        private void ParameterSelector_ItemClick(Object sender, EventArgs e)
        {
            bool succeeded = false;
            int retryCount = 0;

            // WPF has an issue where it will throw an exception if it
            // hasn't been able to populate the ParameterSelector yet.
            while ((!succeeded) && (retryCount < 5))
            {
                try
                {
                    SelectCmdletRegion(PsSpecCmdletParametersContent);

                    // Check that the items have been generated. Otherwise, we will fail to
                    // update the selected parameters.
                    if (!PsSpecCmdletParametersContent.ParameterList.IsLoaded)
                    {
                        return;
                    }

                    List<PsSpecCmdletParameterDetails> someDetails = new List<PsSpecCmdletParameterDetails>();
                    if ((ParameterSelector != null) && (ParameterSelector.SelectedIndex != -1))
                    {
                        someDetails.Add(
                            (PsSpecCmdletParameterDetails)ParameterSelector.Items[ParameterSelector.SelectedIndex]);
                        PsSpecCmdletParametersContent.DataContext = someDetails;
                    }

                    succeeded = true;
                }
                catch (InvalidOperationException)
                {
                    retryCount++;
                    Thread.Sleep(300);
                }
            }
        }

        // The delegate that determines when to display a parameter
        protected bool ParameterTextFilter(object item)
        {
            PsSpecCmdletParameterDetails parameter = item as PsSpecCmdletParameterDetails;

            if (
                (parameter == null) ||
                (String.IsNullOrEmpty(ParameterSearch.Text)) ||
                (ParameterSearch.Text == "Search") ||
                (parameter.Name.IndexOf(ParameterSearch.Text, StringComparison.InvariantCultureIgnoreCase) >= 0))
            {
                return true;
            }
            else
            {
                return false;
            }
        }

        // The delegate that determines when to display a cmdlet
        protected bool CmdletTextFilter(object item)
        {
            PsSpecCmdlet cmdlet = item as PsSpecCmdlet;
            if (cmdlet == null)
                return true;

            return CmdletDesignerUtils.DoesSearchMatchCmdlet(cmdlet, CmdletSearch.Text);
        }

        // The delegate that determines when to display a project
        protected bool ProjectTextFilter(object item)
        {
            PsSpecProject project = item as PsSpecProject;
            if (project == null)
                return true;

            return CmdletDesignerUtils.DoesSearchMatchProject(project, ProjectSearch.Text);
        }

        // Update the cmdlet region header and corresponding data regions
        private void SelectCmdletRegion(UserControl regionContent)
        {
            // Collapse all of the data regions
            foreach (UserControl currentControl in CmdletSectionContent.Children)
            {
                currentControl.Visibility = Visibility.Collapsed;
            }

            if (regionContent == CmdletSummaryContent)
            {
                CmdletSummaryHeader.IsChecked = true;
            }
            else if (regionContent == CmdletDetailsContent)
            {
                CmdletDetailsHeader.IsChecked = true;
            }
            else if (regionContent == SpecExamplesContent)
            {
                SpecExamplesHeader.IsChecked = true;
            }
            else if (regionContent == PsSpecCmdletParametersContent)
            {
                PsSpecCmdletParametersHeader.IsChecked = true;
            }
            else if (regionContent == PsSpecCmdletParameterEntriesContent)
            {
                PsSpecCmdletParameterEntriesHeader.IsChecked = true;
            }

            // Select the given header, and make its data region not collapsed. 
            regionContent.Visibility = Visibility.Visible;
        }

        // Get the verbs
        private ArrayList GetVerbs()
        {
            GetPsSpecVerbCommand command = new GetPsSpecVerbCommand();
            command.ServiceUri = ServiceUri;

            ArrayList results = new ArrayList();
            try
            {
                foreach (PsSpecVerb result in command.Invoke())
                {
                    results.Add(result);
                }
            }
            catch (Exception exception)
            {
                CmdletDesignerUtils.HandleException("Error getting verbs",
                                                    "There were errors retrieving the list of verbs.",
                                                    exception);
            }

            results.Sort();
            return results;
        }

        // Get the nouns
        private List<PsSpecNoun> GetNouns()
        {
            List<PsSpecNoun> results = new List<PsSpecNoun>();
            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];

            if (selectedProject == null)
            {
                MessageBox.Show("Please select a project.");
                return results;
            }

            GetPsSpecNounCommand command = new GetPsSpecNounCommand();
            command.ProjectName = selectedProject.Name;
            command.ServiceUri = ServiceUri;

            try
            {
                foreach (PsSpecNoun result in command.Invoke())
                {
                    results.Add(result);
                }
            }
            catch (Exception exception)
            {
                CmdletDesignerUtils.HandleException("Error getting nouns",
                                                    "There were errors retrieving the list of nouns.",
                                                    exception);
            }

            results.Sort();
            return results;
        }

        // Get the cmdlets for a project
        private List<PsSpecCmdlet> GetCmdlets(string projectName)
        {
            GetPsSpecCmdletCommand command = new GetPsSpecCmdletCommand();
            command.ServiceUri = ServiceUri;
            command.ProjectName = projectName;

            List<PsSpecCmdlet> results = new List<PsSpecCmdlet>();
            try
            {
                foreach (PsSpecCmdlet result in command.Invoke())
                {
                    results.Add(result);
                }
            }
            catch (Exception exception)
            {
                CmdletDesignerUtils.HandleException("Error getting cmdlets",
                                                    "There were errors retrieving the list of cmdlets.",
                                                    exception);
            }

            return results;
        }

        // Get the parameters for a cmdlet
        private List<PsSpecCmdletParameter> GetParameters(string cmdletName, string projectName)
        {
            GetPsSpecCmdletParameterCommand command = new GetPsSpecCmdletParameterCommand();
            command.ServiceUri = ServiceUri;
            command.CmdletName = cmdletName;
            command.ProjectName = projectName;

            List<PsSpecCmdletParameter> results = new List<PsSpecCmdletParameter>();
            try
            {
                foreach (PsSpecCmdletParameter result in command.Invoke())
                {
                    results.Add(result);
                }
            }
            catch (Exception exception)
            {
                CmdletDesignerUtils.HandleException("Error getting parameters",
                                                    "There were errors retrieving the list of parameters.",
                                                    exception);
            }

            return results;
        }

        // Get the parameter set entries for a cmdlet
        private List<PsSpecCmdletParameterSetEntry> GetParameterEntries(string cmdletName, string projectName)
        {
            GetPsSpecCmdletParameterSetEntryCommand command = new GetPsSpecCmdletParameterSetEntryCommand();
            command.ServiceUri = ServiceUri;
            command.CmdletName = cmdletName;
            command.ProjectName = projectName;

            List<PsSpecCmdletParameterSetEntry> results = new List<PsSpecCmdletParameterSetEntry>();
            try
            {
                foreach (PsSpecCmdletParameterSetEntry result in command.Invoke())
                {
                    results.Add(result);
                }
            }
            catch (Exception exception)
            {
                CmdletDesignerUtils.HandleException("Error getting parameter set entries",
                                                    "There were errors retrieving the list of parameter set entries.",
                                                    exception);
            }

            return results;
        }

        // Generate the data for the spec view
        private string GenerateSpecViewData(PsSpecCmdlet current)
        {
            if (current == null)
                return "";

            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                string commandPath = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                    "Get-CmdletDesignerSpecHtml.ps1");

                Command reportCommand = new Command(commandPath);
                reportCommand.Parameters.Add("CmdletName", GetName(current));
                reportCommand.Parameters.Add("ProjectName", current.ProjectName);
                reportCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Commands.Add(reportCommand);

                Collection<PSObject> results;

                try
                {
                    results = pipeline.Invoke();
                }
                catch (Exception exception)
                {
                    CmdletDesignerUtils.HandleException("Error generating spec",
                                                        "There were errors generating the spec.",
                                                        exception);

                    return "";
                }
                HandleErrors(pipeline);

                string htmlOutput = (string)results[0].BaseObject;

                // Replace the "View online" HREF
                string onlineUrl = "http://" + ServiceUri.Host +
                                   String.Format(
                                       "/SpecViewer/Default.aspx?Project={0}&Cmdlet={1}",
                                       HttpUtility.UrlEncode(current.ProjectName),
                                       HttpUtility.UrlEncode(GetName(current)));

                if (ServiceUri.ToString() != DefaultServiceUri)
                {
                    onlineUrl += "&ServiceUri=" + ServiceUri;
                }

                htmlOutput = htmlOutput.Replace("<VIEWONLINE_REPLACEMENT>", onlineUrl);

                return htmlOutput;
            }
        }

        // Refresh the data context for a control to make sure it displays recent updates
        private void RefreshDataContext(UserControl control)
        {
            Object oldData = control.DataContext;
            control.DataContext = null;
            control.DataContext = oldData;

            ICollectionView view = CollectionViewSource.GetDefaultView(control.DataContext);
            if (view != null)
            {
                view.Refresh();
            }
        }


        private void Click_AddUser(Object sender, RoutedEventArgs e)
        {
            //Do add user code.
            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];

            if (selectedProject == null)
            {
                MessageBox.Show("Please select a project.");
                return;
            }

            // Create the Add-PsSpecUserPermission dialog
            AddUser addUserDialog = new AddUser(this);

            if ((bool)addUserDialog.ShowDialog())
            {
                if (addUserDialog.UserName == null)
                {
                    MessageBox.Show("Please enter a valid user name in the form of DOMAIN\alias.");
                    return;
                }

                if (addUserDialog.UserRole == null)
                {
                    MessageBox.Show("Please select a valid user role.");
                    return;
                }

                // New-PsSpecUserPermission -User <Name> -Role <UserRole> -ProjectName <Project>
                AddPsSpecUserPermissionCommand command = new AddPsSpecUserPermissionCommand();
                command.User = addUserDialog.NewUser.Value;
                switch (addUserDialog.UserRole.ToLower())
                {
                    case "specwriter":
                        command.Role = PsSpecProjectRole.SpecWriter;
                        break;
                    case "helpwriter":
                        command.Role = PsSpecProjectRole.HelpWriter;
                        break;
                    case "projectowner":
                        command.Role = PsSpecProjectRole.ProjectOwner;
                        break;
                    case "unspecified":
                        command.Role = PsSpecProjectRole.Unspecified;
                        break;
                }
                command.ProjectName = selectedProject.Name;
                command.ServiceUri = ServiceUri;

                if (command.Role != PsSpecProjectRole.Unspecified)
                {
                    try
                    {
                        command.Invoke().GetEnumerator().MoveNext();
                    }
                    catch (Exception exception)
                    {
                        CmdletDesignerUtils.HandleException("Error creating a new user role",
                                                            "There were errors creating a user role.",
                                                            exception);
                    }
                }
                else
                {
                    MessageBox.Show(
                        "You have specified an invalid user role. Valid entries are: \"SpecWriter, ProjectOwner, HelpWriter\"",
                        "Invalid project role.", MessageBoxButton.OK);
                }

                // Refresh the user premission list
                PopulatePermisionTab(true, selectedProject.Name);
            }
        }

        // Refresh the user names and roles tab
        private void PopulatePermisionTab(bool forceRefresh, String ProjectName)
        {
            // Populate the list of users
            if (forceRefresh || (UsersList == null))
            {
                List<PsSpecUserPermission> usersList = GetUserList(ProjectName);
                List<PsSpecUserPermission> originalUsers = new List<PsSpecUserPermission>();

                // Save the original users, so that we can detect
                // modifications later
                foreach (PsSpecUserPermission user in usersList)
                {
                    originalUsers.Add((PsSpecUserPermission)user);
                }

                Application.Current.Properties["OriginalUsers"] = originalUsers;

                UsersList.DataContext = null;
                UsersList.DataContext = usersList;
                UsersList.SelectedIndex = 0;
            }
        }


        // Determine if a specific user permission has changed
        private bool AreUsersDifferent(PsSpecUserPermission currentOriginalUser,
                                       PsSpecUserPermission currentUpdatedUser)
        {
            return !currentUpdatedUser.Equals(currentOriginalUser);
        }


        // They've clicked "Delete User"
        private void Click_RemoveUser(Object sender, RoutedEventArgs e)
        {
            PsSpecUserPermission selectedUser = UsersList.SelectedItem as PsSpecUserPermission;
            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];

            MessageBoxResult result = MessageBox.Show(
                "Are you sure you wish to delete the '" + selectedUser.User + "' user?",
                "Delete this user?",
                MessageBoxButton.YesNo);
            if (result != MessageBoxResult.Yes)
                return;

            // $currentUser | Remove-PsSpecUserPermission 
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                Command deleteCommand = new Command("Remove-PsSpecUserPermission");
                deleteCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Input.Write(selectedUser);
                pipeline.Commands.Add(deleteCommand);

                Collection<PSObject> results = pipeline.Invoke();
                HandleErrors(pipeline);
            }

            // Refresh the user permission list
            PopulatePermisionTab(true, selectedProject.Name);
        }

        private void FormatBoldText(String text, Brush brush)
        {
            Bold b = new Bold();
            b.Inlines.Add(text);
            PageViewerParagraph.Inlines.Add(b);
            PageViewerParagraph.Inlines.LastInline.Foreground = (Brush)brush;
        }

        private void FormatedText(String text, Brush brush)
        {
            if (text != null)
            {
                PageViewerParagraph.Inlines.Add(text);
                PageViewerParagraph.Inlines.LastInline.Foreground = (Brush)brush;
            }
        }

        private void FormatParagraph(PsSpecHistoryEntry psSpecHistoryResult)
        {
            FormatBoldText("Changed Record", Brushes.Green);
            PageViewerParagraph.Inlines.LastInline.FontWeight = FontWeights.Heavy;
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();
            PageViewerParagraph.Inlines.Add("------------------------------------------------------");
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Cmdlet Name:\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.CmdletName), Brushes.Gray);
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Property:\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.PropertyName), Brushes.Gray);
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Action:\t\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.Action.ToString()), Brushes.Gray);
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Old Value:\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.OldValue), Brushes.Black);
            if (psSpecHistoryResult.OldValue != null)
            {
                BrushConverter br = new BrushConverter();
                PageViewerParagraph.Inlines.LastInline.Background = (Brush)br.ConvertFrom("#FFFFA7A7");
            }
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("New Value:\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.NewValue), Brushes.Black);
            if (psSpecHistoryResult.NewValue != null)
            {
                PageViewerParagraph.Inlines.LastInline.Background = Brushes.Yellow;
            }
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Notes:\t\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.Notes), Brushes.Black);
            if (psSpecHistoryResult.Notes != null)
            {
                PageViewerParagraph.Inlines.LastInline.Background = Brushes.Yellow;
            }
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Parameter:\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.ParameterName), Brushes.Gray);
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Last Updated:\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.LastUpdated.ToString()), Brushes.Gray);
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            FormatBoldText("Changed by:\t", Brushes.Black);
            FormatedText((psSpecHistoryResult.ChangedBy), Brushes.Gray);
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();

            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();
            PageViewerParagraph.Inlines.LastInline.ContentEnd.InsertLineBreak();
        }

        // They've clicked on the history  header
        private void Click_GetHistory(Object sender, RoutedEventArgs e)
        {
            PsSpecProject selectedProject = (PsSpecProject)Application.Current.Properties["SelectedProject"];
            Command historyCommand = new Command("Get-PsSpecHistory");
            // $Cmdlets | Get-PsSpecHistory -from <date> -To <date> -ChangeType 
            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                //Project, Cmdlet
                switch (ChangeType.Items.SelectionBoxItem.ToString().ToLower())
                {
                    case "cmdlet":
                        historyCommand.Parameters.Add("ChangeType", PsSpecHistoryChangeType.Cmdlet);
                        Command GetCmdlets = new Command("Get-PsSpecCmdlet");
                        GetCmdlets.Parameters.Add("ServiceUri", ServiceUri);
                        GetCmdlets.Parameters.Add("ProjectName", selectedProject.Name);
                        if ((CmdletNameChanges.Value != null) && (CmdletNameChanges.Value != ""))
                        {
                            GetCmdlets.Parameters.Add("Name", CmdletNameChanges.Value);
                        }

                        pipeline.Commands.Add(GetCmdlets);
                        break;

                    case "project":
                        historyCommand.Parameters.Add("ChangeType", PsSpecHistoryChangeType.Project);
                        Command GetPsProject = new Command("Get-PsSpecProject");
                        GetPsProject.Parameters.Add("ServiceUri", ServiceUri);
                        GetPsProject.Parameters.Add("Name", selectedProject.Name);

                        pipeline.Commands.Add(GetPsProject);
                        break;
                    default:
                        MessageBox.Show(
                            "Please select valid change type value.\nValid types are: \"Project\", \"Cmdlet\"",
                            "Invalid Change type value", MessageBoxButton.OK, MessageBoxImage.Warning);
                        return;
                }
                DateTime from = new DateTime();
                DateTime to = new DateTime();

                bool isFromDate = DateTime.TryParse(HistoryFromDate.Value, out from);
                bool isToDate = DateTime.TryParse(HistoryToDate.Value, out to);
                if (isFromDate && isToDate)
                {
                    historyCommand.Parameters.Add("From", from);
                    historyCommand.Parameters.Add("To", to);
                    historyCommand.Parameters.Add("ServiceUri", ServiceUri);
                    historyCommand.Parameters.Add("ErrorAction", "SilentlyContinue");
                    pipeline.Commands.Add(historyCommand);

                    Collection<PSObject> psResults = new Collection<PSObject>();
                    psResults = pipeline.Invoke();

                    PageViewerParagraph.Inlines.Clear();
                    PageViewer.FlowDirection = FlowDirection.LeftToRight;
                    PageViewerParagraph.TextAlignment = TextAlignment.Left;
                    foreach (PSObject result in psResults)
                    {
                        PsSpecHistoryEntry psSpecHistoryResult = (PsSpecHistoryEntry)result.ImmediateBaseObject;
                        FormatParagraph(psSpecHistoryResult);
                    }
                    HandleErrors(pipeline);
                    if (psResults.Count == 0)
                    {
                        MessageBox.Show("There were no changes found within the specified date range",
                                        "No Changes Found!", MessageBoxButton.OK, MessageBoxImage.Warning);
                    }
                }
                else
                {
                    MessageBox.Show("Invalid date format. Please make sure to type a valid date value.",
                                    "Invalid Date Format!", MessageBoxButton.OK, MessageBoxImage.Warning);
                }
            }
        }

        private void Click_GoToHistoryPage(Object sender, RoutedEventArgs e)
        {
            try
            {
                int pageNumber = Int16.Parse(JumpToSpecificPage.Text);
                PageViewer.GoToPage(pageNumber);
            }
            catch
            {
                MessageBox.Show("Invalid integer format. Please make sure to type a valid integer number.",
                                "Invalid Integer Format!", MessageBoxButton.OK, MessageBoxImage.Warning);
            }
        }

        #region Nested type: UpdateProjectsDelegate

        private delegate void UpdateProjectsDelegate();

        #endregion

        private void Click_Toggle(object sender, RoutedEventArgs e)
        {

        }

        private void Click_Login(object sender, RoutedEventArgs e)
        {
            // will trigger IClientFormsAuthenticationCredentialsProvider login window
            if (Membership.ValidateUser(String.Empty, String.Empty))
            {
                //MessageBox.Show("Logged in successfully.", "Success", MessageBoxButton.OK, MessageBoxImage.Information);

                lblUser.Content = "User: " + Thread.CurrentPrincipal.Identity.Name;

                btnLogin.Visibility = Visibility.Collapsed;
                btnLogout.Visibility = Visibility.Visible;
                this.IsLoggedIn = true;
            }
        }

        private void Click_Logout(object sender, RoutedEventArgs e)
        {
            // Get an instance of the ClientFormsAuthenticationMembershipProvider
            // to use the Logout function which is not present on Membership.Provider
            ClientFormsAuthenticationMembershipProvider clientFormAuthProvider =
              (ClientFormsAuthenticationMembershipProvider)Membership.Provider;

            try
            {
                clientFormAuthProvider.Logout();
            }
            catch (WebException ex)
            {
                MessageBox.Show("Unable to access the authentication service." +
                  Environment.NewLine + "Logging off locally only.", "Warning",
                  MessageBoxButton.OK, MessageBoxImage.Warning);

                ConnectivityStatus.IsOffline = true;
                clientFormAuthProvider.Logout();
                ConnectivityStatus.IsOffline = false;
            }

            lblUser.Content = "User: Guest";
            lblRole.Content = "Role: Guest";

            btnLogout.Visibility = Visibility.Collapsed;
            btnLogin.Visibility = Visibility.Visible;

            this.IsLoggedIn = false;
        }

        private void Click_FunctionGenerator(object sender, RoutedEventArgs e)
        {
            // Get the currently open cmdlet
            PsSpecCmdlet current = CmdletSummaryContent.DataContext as PsSpecCmdlet;

            if (current == null)
                return;

            using (Pipeline pipeline = _runspace.CreatePipeline())
            {
                string commandPath = Path.Combine(
                    Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
                    "Get-FunctionTemplate.ps1");

                Command reportCommand = new Command(commandPath);
                reportCommand.Parameters.Add("CmdletName", GetName(current));
                reportCommand.Parameters.Add("ProjectName", current.ProjectName);
                reportCommand.Parameters.Add("ServiceUri", ServiceUri);

                pipeline.Commands.Add(reportCommand);

                Collection<PSObject> results;

                try
                {
                    results = pipeline.Invoke();
                }
                catch (Exception exception)
                {
                    CmdletDesignerUtils.HandleException("Error generating spec",
                                                        "There were errors generating the spec.",
                                                        exception);

                    return;
                }

                HandleErrors(pipeline);

                string output = "<pre>";

                foreach (PSObject result in results)
                    output += "\n" + HttpUtility.HtmlEncode((string)result.BaseObject);

                output += "</pre>";

                HtmlViewWindow htmlView = new HtmlViewWindow(output, this);
                htmlView.Show();
            }
        }
    }
}